//============================================================================
// Copyright (C) 2003-2013 Brett R. Jones 
// All Rights Reserved
//
// You may redistribute and/or modify for non commercial and commercial uses 
// provided this copyright notice remains in place and is not modified
//
// This code is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//
// brettjones1900@gmail.com
// http://www.p2panarchy.com
//============================================================================

// VxWebPageImp.cpp : Defines the entry point for the DLL application.
// 

#include "VxWebServerLib.h"

//============================================================================
//! send standard http error to browser
RCODE SendHttpErr( VxWebSkt * poSkt, int iErrIdx )
{
	//send error
	RCODE rc = iErrIdx;
	static char szMsg[512];
	static const char *szStatMsgs [] = {
								"200 OK",
								"201 Created",
								"202 Accepted",
								"204 No Content",
								"301 Moved Permanently",
								"302 Moved Temporarily",
								"304 Not Modified",
								"400 Bad Request",
								"401 Unauthorized",
								"403 Forbidden",
								"404 Not Found",
								"500 Internal Server Error",
								"501 Not Implemented",
								"502 Bad Gateway",
								"503 Service Unavailable"
								};
	#define NUMSTATMSGS sizeof(szStatMsgs) / sizeof(szStatMsgs[0])

	if( rc < 0 || rc > NUMSTATMSGS)
	{
		vx_assert( FALSE );
		return -1;
	}

	sprintf(szMsg, "<body><h1>%s</h1></body>",
				 szStatMsgs[rc]);

	return poSkt->SendData(	szMsg, 
								(int)strlen( szMsg ),
								TRUE );

}
//============================================================================
//! get real file name from website alias ( if has alias )
RCODE VxWebServer::GetWebSiteRealFileName(	std::string& strWebFileName, EWbMyFiles& peRetMyFileType )
{
	peRetMyFileType = eWbMyFilesNone;
#ifdef USE_WEB_FILESHARE
	char as8Buf[ MAX_PATH ];
	const char * pTemp = strWebFileName.c_str();
	BOOL bAliasFound = false;
	// strip off leading slash
	if( '/' == pTemp[0] )
	{
		strcpy( as8Buf, &pTemp[1] );
	}
	else
	{
		strcpy( as8Buf, pTemp );
	}
	if( 0 == strncmp( as8Buf, WEB_MY_TC_PICTURE_ALIAS, strlen( WEB_MY_TC_PICTURE_ALIAS ) ) )
	{
		// its my picture.. get real file
		strWebFileName = GetMyPictureRealFile();
		bAliasFound = true;
	}
	else
	{
		for( int i = 1; i < eWbMyFilesError; i++ )
		{
			if( false == IsMyFilesEnabled( (EWbMyFiles)i ) )
			{
				// not enabled
				continue;
			}
			char * pAlias = GetMyFilesAlias( (EWbMyFiles)i );
			int iAliasLen = (int)strlen( pAlias );
			if( 0 >= iAliasLen )
			{
				log_msg( 0, "VxWebServer::GetRealFileName: zero alias of type %d\n", i );
				vx_assert( false );
				continue;
			}
			if( 0 == strncmp( as8Buf, pAlias, iAliasLen ) )
			{
				// found alias
				if( (int)strlen( as8Buf ) > iAliasLen )
				{
					std::string strAliasPath;
					std::string strAliasFile;
					VxSeperatePathAndFile(	as8Buf,			// path and file name			
											strAliasPath,	// return path to file
											strAliasFile );	// return file name
					if( 0 == strcmp( strAliasFile.c_str(), "tc_index.htm" ) )
					{
						// is a index of shared files in website directory
						strWebFileName = GetWebSiteDir() + as8Buf;
					}
					else
					{
						// is a shared file
						std::string strAliasDir = GetMyFilesDir( (EWbMyFiles)i );
						strWebFileName = strAliasDir + &as8Buf[ iAliasLen ];
					}
					bAliasFound = true;
					* peRetMyFileType = (EWbMyFiles)i;
					break;
				}
			}
		}
	}
	if( false == bAliasFound )
	{
		// no alias so use root of website directory
		strWebFileName = GetWebSiteDir() + as8Buf;
	}
	if( VxFileExists( strWebFileName.c_str() ) )
	{
		return 0;
	}
	return -1;
#else // no fileshare
	// no alias so use root of website directory
	strWebFileName = getWebSiteDir() + strWebFileName;

	if( VxFileExists( strWebFileName.c_str() ) )
	{
		return 0;
	}
	return -1;
#endif// USE_WEB_FILESHARE
}

//============================================================================
//! hande incomming data from socket
RCODE VxWebServer::HandleWebData( VxWebSkt * poSkt )
{
	if( false == isWebServerAvailable() )
	{
		poSkt->CloseSkt();
		return -1;
	}
	int iDataLen = poSkt->GetSktBufDataLen();
	if( iDataLen < 15 )
	{
		// not enough to work with
		return 0;
	}
	char as8Buf[ 1024 ];
	std::string		strPwd;
	EHttpReqType eHttpReqType = eHttpReqUnknown;
	char * pSktBuf = (char *)poSkt->GetSktReadBuf();

	if( 0 == strstr( pSktBuf, "\r\n\r\n" ) )
	{
		// no terminator of command
		poSkt->SktBufAmountRead(0);
		return 0;
	}
	char szSeps[] = " \n";
	char *cpToken;
	std::string csFileName;
	RCODE rc = 0;
	int iBytesUsed = 0;

	char * pCurParse = pSktBuf;
	char * pNextParse;
	while( NULL != ( pNextParse = strstr( pCurParse, "\r\n\r\n" ) ) )
	{
		iBytesUsed += (int)(pNextParse - pCurParse) + 4;
		pNextParse += 4;

		//
		// Don't let requests include ".." characters
		// in requests
		//
		if (strstr( pCurParse, "..") != NULL)
		{
			// Send "bad request" error
			SendHttpErr( poSkt,  HTTP_STATUS_BADREQUEST );
			return poSkt->CloseSkt();
		}

		//
		// Determine request method
		//
		cpToken = strtok( pCurParse, szSeps);
		if( 0 == stricmp( cpToken, "GET" ) )
		{
			// getting file.
			eHttpReqType = eHttpReqGet;
		}
		else if( 0 == stricmp( cpToken, "POST" ) )
		{
			// posting password
			eHttpReqType = eHttpReqPost;
		}
		else
		{
			// Send "not implemented" error
			return SendHttpErr( poSkt, HTTP_STATUS_NOTIMPLEMENTED );
		}

		//
		// Get the file name
		//
		cpToken = strtok(NULL, szSeps);
		if (cpToken == NULL)
		{
			// Send "bad request" error
			return SendHttpErr( poSkt, HTTP_STATUS_BADREQUEST );
		}
		if (strlen(cpToken) > 1)
		{
			memset( as8Buf, 0, sizeof( as8Buf ));
			int iIdx = 0;
			while( 0 != cpToken[ iIdx ] )
			{
				if( cpToken[ iIdx ] == '%' )
				{
					if( (cpToken[ iIdx + 1 ] == '5' ) &&
						(cpToken[ iIdx + 2 ] == 'C' ) )
					{
						as8Buf[ strlen( as8Buf ) ] = '/';
						iIdx += 3;
						continue;
					}
					if( (cpToken[ iIdx + 1 ] == '2' ) &&
						(cpToken[ iIdx + 2 ] == '0' ) )
					{
						as8Buf[ strlen( as8Buf ) ] = ' ';
						iIdx += 3;
						continue;
					}
				}
				as8Buf[ strlen( as8Buf ) ] = cpToken[ iIdx ];
				iIdx++;
			}
			csFileName = as8Buf;
		}
		else
		{
			std::string csIdxFile = getWebSiteDir() + "index.htm";
			if( VxFileExists( csIdxFile.c_str() ) )
			{
				csFileName = "index.htm";
			}
			else
			{
				csIdxFile = getWebSiteDir() + "index.html";
				if( VxFileExists( csIdxFile.c_str() ) )
				{
					csFileName = "index.html";
				}
				else
				{
					csFileName = "rc_main_index.htm";
				}
			}
		}
		if( eHttpReqPost == eHttpReqType )
		{
			// we need to parse the pwd also
			BOOL bPwdOk = true;
			char * pTemp = strstr( pNextParse, "tc_pwd" );
			if( NULL == pTemp )
			{
				bPwdOk = false;
				log_msg( 0, "VxWebServer::HandleWebData: could not parse pwd\n" );
				return SendHttpErr( poSkt, HTTP_STATUS_NOTFOUND );
			}
			if( bPwdOk )
			{
				pTemp = pTemp + strlen( "tc_pwd" );
				if( '=' != pTemp[0] )
				{
					bPwdOk = false;
				}
				else
				{
					pTemp++;
					strPwd = pTemp;
					if( ( 0 == strPwd.size() ) ||
						( strPwd.size() > 63 ) )
					{
						bPwdOk = false;
					}
				}
			}
			if( false == bPwdOk )
			{
				log_msg( 0, "VxWebServer::HandleWebData: invalid pwd %s\n", strPwd.c_str() );
				return SendHttpErr( poSkt, HTTP_STATUS_UNAUTHORIZED );
			}
		}
		EWbMyFiles eFileType;	// My shared file type
		rc = GetWebSiteRealFileName( csFileName, eFileType );
		if( rc )
		{
			// could not get real file name
			log_msg( 0, "VxWebServer::HandleWebData: could not get real file name for %s\n", csFileName.c_str() );
			return SendHttpErr( poSkt, HTTP_STATUS_NOTFOUND );
		}
		poSkt->QueWebsiteFile( csFileName.c_str(), eFileType, eHttpReqType, strPwd.c_str() );
		strPwd = "";
		pCurParse = pNextParse; // done with this chunk
	}
	poSkt->SktBufAmountRead( iBytesUsed );
	return 0;
}
